// cmake ../ -G "MinGW Makefiles"
#include<iostream>
#include<cstring>
#include"global.h"
#include"config.h"
#include"robot.h"
#include"berth.h"
#include"logger.h"
#include"astar.h"

using namespace std;

const char OK[] = "OK";
int current_money;
int current_frame;

char map[MAP_SIZE][MAP_SIZE];  // 地图
unordered_set<Cargo, CargoHash> CargoSet; // 全局货物集

extern int boat_capacity;        // 船容量
extern Boat boats[BOAT_NUM];     // 船儿们
extern Robot robots[ROBOT_NUM];  // 机器人儿们
extern Berth berths[BERTH_NUM];  // 港口们

void Init();
void InitRobot();
void Input();
void ControlRobot();
void ControlBoat();
void SetRouteToCargo(int i);

int main(){
    Init(); // 初始化
    
    while(current_frame < TOTAL_FRAME){
        current_frame++;
        // 获取输入
        Input();
        // 设置机器人动作
        ControlRobot();
        // 设置船动作
        ControlBoat();
        puts("OK");
        fflush(stdout);
    }

    // For DEBUG
    fprintf(stderr, "boat_capacity = %d\n", boat_capacity);
    for(int i = 0;i < BERTH_NUM;i++){
        fprintf(stderr, "berth[%d]:totalcargo = %d, misscargo = %d, cureentcargo = %d\n", i, berths[i].totalcargo, berths[i].misscargo, berths[i].currentcargo);
    }
}

void Init(){
    int robot_index = 0;
    // Init map
    for(int i = 0; i < MAP_SIZE; i ++){
        for(int j = 0;j < MAP_SIZE;j++){
            scanf("%c", &map[i][j]);
            if(map[i][j] == 'A'){
                map[i][j] = '.'; // Robot点转化为普通道路
                robots[robot_index].p = Point(i, j);
                robot_index++;
            }
        }
        getchar(); // get the "\n"
    }
    
    // Init Berth
    priority_queue<Berth*, vector<Berth*>, BerthCompare> heap; // 将Berth按照score排序
    for(int i = 0; i < BERTH_NUM; i ++){
        int id;
        scanf("%d", &id);
        cin >> berths[i];
        berths[i].idx = i;
        berths[i].SetScore();
        heap.push(&berths[i]);

        cerr << "berth[" << i << "]: " << berths[i] << endl;
    }

    // 按照港口评分先后，将最近的机器人绑定到港口
    while(heap.size() > 0){
        Berth* b = heap.top();
        heap.pop();
        int min_distance = MAX_DISTANCE;
        int chosen_robot = -1;
        for(int i = 0;i < ROBOT_NUM;i++){
            if(robots[i].belonging == nullptr){ // 未绑定
                list<Point> route = FindRoute(robots[i].p, b->p ,map);
                if(route.size() > 0 && route.size() < min_distance){  // 能走通
                    chosen_robot = i;
                    min_distance = route.size();
                }
            }
        }
        if(chosen_robot != -1){ // 选择了某个机器人
            robots[chosen_robot].belonging = b;
            fprintf(stderr, "robots[%d] bind to berth at (%d %d), score = %.2f\n", chosen_robot, b->p.x, b->p.y, b->score);
            (*b).UpdateScore();
            (*b).close = false;
            heap.push(b);
        }
    }

    for(int i = 0;i <ROBOT_NUM;i++){
        if(robots[i].belonging == nullptr){ // 这机器人凉了
            fprintf(stderr, "robots[%d] dead forever, RIP...\n", i);
            robots[i].dead = -1;
        }
    }

    scanf("%d\n", &boat_capacity);
    char okk[100];
    scanf("%s", okk);
    cout << "OK" << endl;
    fflush(stdout);
}

void Input(){
    scanf("%d%d\n", &current_frame, &current_money);

    // 如果港口剩余时间不够往返，且没有船正在驶来，关闭港口
    for(int i = 0;i < BERTH_NUM;i++){
        if(current_frame + berths[i].transport_time * 2 + boat_capacity / berths[i].loading_speed + 1 > TOTAL_FRAME && berths[i].boatcoming == 0){
            berths[i].close = true;
        }
    }

    // 获取货物信息
    int num;
    scanf("%d\n", &num);

    // Get new cargos and add to berth's queue according to distance
    for(int i = 0; i < num; i ++){
        int x, y, val;
        scanf("%d%d%d\n", &x, &y, &val);
        CargoSet.insert(Cargo(Point(x, y), val, current_frame)); // 将新的货物加入到cargoset
        for(int j = 0; j < BERTH_NUM; j ++){
            list<Point> route = FindRoute(berths[j].p, Point(x, y), map);
            Cargo cargo(Point(x, y), val, current_frame, route.size());
            berths[j].cargo_set.insert(cargo); // 将货物加入港口优先队列
        }
    }

    for(int i = 0; i < ROBOT_NUM; i ++){
        cin >> robots[i];
    }

    for(int i = 0; i < BOAT_NUM; i ++){
        cin >> boats[i];
    }
    char okk[100];
    scanf("%s", okk);
    if(strcmp(okk, OK) != 0){
        fprintf(stderr, "[ERR]Frame%d Retrive Failed!\n", current_frame);
    }
}

void ControlRobot(){
    for(int i = 0; i < ROBOT_NUM; i ++){
        // 这个机器人自闭了
       if(robots[i].dead != 0){
            robots[i].dead--;
            if(robots[i].dead == 0){
                map[robots[i].p.x][robots[i].p.y] = robots[i].map_restore; // 复活吧！我的机器人!!!(其实就是恢复地图)
            }else{
                continue;
            }
        }

        if(robots[i].belonging)

        // 这个机器人无所事事，给它安排点活
        if(robots[i].target.x == -1 && robots[i].belonging->cargo_set.size() > 0){
            robots[i].SetRouteToCargo();
        }

        // 到港口了，准备交货
        if(robots[i].ArriveAtBerth()){
            robots[i].Deliver(i);
        }
        
        if(robots[i].p == robots[i].target){ // 到达Target位置
            if(robots[i].p == robots[i].belonging->p){ // 空手到达所属港口，概率不大但还是会发生，废物
                robots[i].Deliver(i);
            }else{ // 到达cargo处，拿起并返回港口   
                printf("get %d\n", i); // 拿货
                if(robots[i].belonging->close == true){ // 所属港口已关闭
                    robots[i].ReBindBerth();
                    if(robots[i].belonging == nullptr){ // 同志可以歇息了
                        robots[i].dead = -1;
                        break;
                    }
                }
                robots[i].SetRouteToBerth();
            }
        }else if(robots[i].route.size() == 0){  // 有Target但没路径，它可能刚才在避障导致丢失了路径...
            robots[i].ResetRoute();
        }

        // 尝试移动
        if(robots[i].route.size() > 0){
            bool wait = false;     // 是否原地等待
            bool retreat = false;  // 是否逃避(后退一步)
            // 退避策略：
            // 距离<=2, index最小的Robot走, index大的原地等待
            // 即将撞上, index最小的Robot重新规划路径, index大的原地等待
            for(int j = 0;j < i;j++){
                if(robots[j].dead != 0) continue; 
                if(robots[i].p.Distance(robots[j].p) <= 2){
                    wait = true;
                }
            }
            if(wait == false){
                Point next = robots[i].route.front();
                robots[i].route.pop_front();
                if(next.Distance(robots[i].p) != 1 || map[next.x][next.y] == '#'){  // 跳帧了，重新规划路径
                // cerr << "robots["<< i << "] regenerate route for frame err" << endl;
                    robots[i].ResetRoute();
                    if(robots[i].route.size() == 0){  // 有个SB把路堵了，多么伤心的事情，换个货吧
                        robots[i].target.x = -1;
                        continue;
                    }
                    next = robots[i].route.front();
                    robots[i].route.pop_front();
                }
                for(int j = i + 1;j < ROBOT_NUM;j++){
                    if(robots[j].dead != 0) continue;
                    // if(robots[i].p.Distance(robots[j].p) <= 2){ // 马上撞上了，避撞
                    if(next == robots[j].p){
                    // fprintf(stderr, "robots[%d] at (%d %d) call AvoidCollision for robots[%d] at (%d %d)\n", i, robots[i].p.x, robots[i].p.y, j, robots[j].p.x, robots[j].p.y);
                        robots[i].AvoidCollision(i, next, retreat);
                        break;
                    }   
                }

                // Go
                if(robots[i].dead == 0){
                    robots[i].Go(i, next, retreat);
                }
            }
        }
    }
}

void ControlBoat(){
    if(current_frame < BOAT_START_FRAME) return; // 先等一段时间，不然不好选对象
    for(int i = 0;i < BOAT_NUM;i++){
        if(boats[i].status == 1){ // 在港
            if(boats[i].pos == -1){ // 回港
                boats[i].GoToBerth(i);
            }
            else if(boats[i].wait <= 0){ // 出发
                berths[boats[i].pos].boatcoming--;
                boats[i].Deliver(i);
            }else{
                boats[i].wait--;
            }
        }
    }
}


